package bg.consulting.labo.rtp;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.net.InetAddress;

import javax.media.ControllerErrorEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.Player;
import javax.media.RealizeCompleteEvent;
import javax.media.StartEvent;
import javax.media.control.BufferControl;
import javax.media.protocol.DataSource;
import javax.media.rtp.Participant;
import javax.media.rtp.RTPControl;
import javax.media.rtp.RTPManager;
import javax.media.rtp.ReceiveStream;
import javax.media.rtp.ReceiveStreamListener;
import javax.media.rtp.SessionAddress;
import javax.media.rtp.SessionListener;
import javax.media.rtp.event.ByeEvent;
import javax.media.rtp.event.InactiveReceiveStreamEvent;
import javax.media.rtp.event.NewParticipantEvent;
import javax.media.rtp.event.NewReceiveStreamEvent;
import javax.media.rtp.event.ReceiveStreamEvent;
import javax.media.rtp.event.RemotePayloadChangeEvent;
import javax.media.rtp.event.SessionEvent;
import javax.media.rtp.event.StreamMappedEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


/**
 * AVReceive2 to receive RTP transmission using the RTP API.
 */
public class BgReceiveRTP implements ReceiveStreamListener, SessionListener, ControllerListener {

	private String addr;
	private int ttl = 1;
	private int port ;
	private RTPManager rtpManager;
	private JFrame frame = new JFrame();
	private JPanel panel = new JPanel();
	private JLabel labelEvent = new JLabel("");
	private JLabel labelStream = new JLabel(" ");
	private JLabel labelControllerUpdate = new JLabel("");
	private JLabel labelComment = new JLabel("");
	private JPanel panelPlayer = new JPanel();
	private Player player;

	public BgReceiveRTP() {
		this("192.168.1.10",3000);
	}
	
	public BgReceiveRTP(String adr, int port) {
		this.addr=adr;
		this.port=port;
		
	}

	public void initialize() throws Exception {

		InetAddress ipAddr;
		SessionAddress localAddr = new SessionAddress();
		SessionAddress destAddr;

		System.out.println("  - Open RTP session for: addr: " + this.addr + " port: " + this.port + " ttl: " + this.ttl);

		rtpManager = (RTPManager) RTPManager.newInstance();
		rtpManager.addSessionListener(this);
		rtpManager.addReceiveStreamListener(this);

		ipAddr = InetAddress.getByName(this.addr);

		if (ipAddr.isMulticastAddress()) {
			// local and remote address pairs are identical:
			localAddr = new SessionAddress(ipAddr, this.port, this.ttl);
			destAddr = new SessionAddress(ipAddr, this.port, this.ttl);
		} else {
			localAddr = new SessionAddress(InetAddress.getLocalHost(), this.port);
			destAddr = new SessionAddress(ipAddr, this.port);
		}

		rtpManager.initialize(localAddr);

		// You can try out some other buffer size to see
		// if you can get better smoothness.
		BufferControl bc = (BufferControl) rtpManager.getControl("javax.media.control.BufferControl");
		if (bc != null)
			bc.setBufferLength(350);

		rtpManager.addTarget(destAddr);
		this.initPanel();
		this.setLabelStream("Waiting t: " + port, Color.yellow);
		this.setLabelEvent("Waiting  " + port, Color.yellow);

	}

	private void initPanel() {
		this.panel.setLayout(new GridLayout(0, 1));
		this.panel.add(this.labelEvent);
		this.panel.add(this.labelStream);
		this.panel.add(this.labelControllerUpdate);
		this.panel.add(this.labelComment);
		this.panel.add(this.panelPlayer);
		this.labelEvent.setOpaque(true);
		this.labelStream.setOpaque(true);
		this.labelControllerUpdate.setOpaque(true);
		Dimension dim = new Dimension(300, 30);
		this.labelComment.setPreferredSize(dim);
		this.labelControllerUpdate.setPreferredSize(dim);
		this.labelEvent.setPreferredSize(dim);
		this.labelStream.setPreferredSize(dim);

	}

	

	/**
	 * Close the players and the session managers.
	 */
	private void close() {
		// close the RTP session.
		if (this.rtpManager!= null) {
			this.rtpManager.removeTargets("Closing session BgReceiveRTP");
			this.rtpManager.dispose();
			this.rtpManager = null;
		}
	}



	private void setLabelStream(String text, Color colr) {
		this.labelStream.setText(text);
		this.labelStream.setBackground(colr);
	}

	private void setLabelEvent(String text, Color colr) {
		this.labelEvent.setText(text);
		this.labelEvent.setBackground(colr);
	}

	private void setLabelController(String text, Color colr) {
		this.labelControllerUpdate.setText(text);
		this.labelControllerUpdate.setBackground(colr);
	}

	private void setLabelComment(String text) {
		System.out.println(text);
		this.labelComment.setText(text);
		this.labelComment.setBackground(Color.white);
	}
	
	/**
	 * SessionListener.
	 */
	public void update(SessionEvent evt) {
		this.setLabelComment("--- listener update session :"+evt);
		if (evt instanceof NewParticipantEvent) {
			Participant p = ((NewParticipantEvent) evt).getParticipant();
			System.out.println("  - A new participant had just joined: " + p.getCNAME());
			setLabelEvent("SessionEvent " + p.getCNAME(), Color.green);
		}
	}

	/**
	 * ReceiveStreamListener
	 */
	public void update(ReceiveStreamEvent evt) {
		this.setLabelComment("--- listener update  ReceiveStreamEvent : " + evt);

		RTPManager mgr = (RTPManager) evt.getSource();
		Participant participant = evt.getParticipant(); // could be null.
		ReceiveStream stream = evt.getReceiveStream(); // could be null.

		if (evt instanceof RemotePayloadChangeEvent) {
			this.setLabelStream("ChangeEvent : not supported", Color.RED);
			System.out.println(" xxx RemotePayloadChangeEvent  - Received an RTP PayloadChangeEvent.");
			System.out.println(" ----                   Sorry, cannot handle payload change.");
		}else if (evt instanceof NewReceiveStreamEvent) {
			this.setLabelStream("NewReceiveStream ", Color.GREEN);

			try {
				stream = ((NewReceiveStreamEvent) evt).getReceiveStream();
				DataSource ds = stream.getDataSource();

				// Find out the formats.
				RTPControl ctl = (RTPControl) ds.getControl("javax.media.rtp.RTPControl");
				String format = "";
				String participantStr = "";
				if (ctl != null) {
					format = "" + ctl.getFormat();
				}

				if (participant != null) {
					participantStr = participant.getCNAME();
				}
				this.setLabelComment("Recevied new RTP stream: " + format + " de " + participantStr);

				// create a player by passing datasource to the Media Manager
				this.player = javax.media.Manager.createPlayer(ds);
				this.player.realize();
				this.player.addControllerListener(this);

			} catch (Exception e) {
				e.printStackTrace();
				this.setLabelComment("Exception "+e.getMessage());
			}

		}else if (evt instanceof StreamMappedEvent) {
			this.setLabelStream("StreamMapped", Color.ORANGE);
			if (stream != null && stream.getDataSource() != null) {
				DataSource ds = stream.getDataSource();
				// Find out the formats.
				RTPControl ctl = (RTPControl) ds.getControl("javax.media.rtp.RTPControl");
				System.out.println("  - The previously unidentified stream ");
				if (ctl != null)
					System.out.println("      " + ctl.getFormat());
				System.out.println("      had now been identified as sent by: " + participant.getCNAME());
			}
		}else if (evt instanceof ByeEvent) {
			this.setLabelStream("byby", Color.BLUE);
		}else if (evt instanceof InactiveReceiveStreamEvent){
			this.setLabelStream("InactiveReceiveStreamEvent", Color.GREEN);
		}

	}

	/**
	 * ControllerListener for the Players.
	 */
	public void controllerUpdate(ControllerEvent ce) {
		this.setLabelComment("--- controllerUpdate ControllerEventt : " + ce);
		System.out.println("CCC -------------   controllerUpdate ControllerEvent " + ce);
		boolean b = true;
		if (player == null) {
			this.setLabelStream("Player is null !!!", Color.RED);
			return;
		}
		// Get this when the internal players are realized.
		if (ce instanceof RealizeCompleteEvent) {
			this.setLabelController("RealizeComplete ", Color.GREEN);
			this.panelPlayer.removeAll();
			this.panelPlayer.add(this.player.getControlPanelComponent());
		
			Component visualComponent = this.player.getVisualComponent();
			if (visualComponent != null) {
				this.panelPlayer.add(visualComponent);
			}
			this.frame.pack();
			this.player.start();
		}
		
		if (ce instanceof StartEvent){
			this.setLabelController("Start ", Color.GREEN);
		}

		if (ce instanceof ControllerErrorEvent) {
			this.setLabelController("ControllerError", Color.RED);
			player.removeControllerListener(this);
			System.out.println("AVReceive2 internal error: " + ce);
		}
	}

	/**
	 * A utility class to parse the session addresses.
	 */
	

	public static void main(String argv[]) throws Exception {
		BgReceiveRTP avReceive = new BgReceiveRTP();
		avReceive.initialize();
		avReceive.frame.add(avReceive.panel);
		avReceive.frame.pack();
		avReceive.frame.setVisible(true);
	}

}
